package zkclient

import (
	"context"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/rpc"
)

type ZkSyncClient struct {
	clients []*ethclient.Client
	urls    []string
	current int
	mu      sync.RWMutex
}

// NewZkSyncClient creates a new ZkSync client with multiple RPC endpoints
func NewZkSyncClient(rpcURLs []string) (*ZkSyncClient, error) {
	if len(rpcURLs) == 0 {
		return nil, fmt.Errorf("no RPC URLs provided")
	}

	clients := make([]*ethclient.Client, 0, len(rpcURLs))
	for _, url := range rpcURLs {
		httpClient := &http.Client{
			Timeout: 30 * time.Second, // 本地节点可以设置更长的超时时间
			Transport: &http.Transport{
				MaxIdleConns:        100,
				MaxIdleConnsPerHost: 100,
				IdleConnTimeout:     90 * time.Second,
				// 本地节点不需要 TLS
				DisableCompression: true, // 本地连接可以禁用压缩
			},
		}

		// 使用自定义 HTTP 客户端创建 RPC 客户端
		rpcClient, err := rpc.DialOptions(context.Background(), url, rpc.WithHTTPClient(httpClient))
		if err != nil {
			fmt.Printf("Failed to create RPC client for %s: %v\n", url, err)
			continue
		}

		// 使用 RPC 客户端创建 ethclient
		client := ethclient.NewClient(rpcClient)

		// 测试连接
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()

		// 尝试获取区块号来测试连接
		blockNumber, err := client.BlockNumber(ctx)
		if err != nil {
			fmt.Printf("Failed to connect to local node %s: %v\n", url, err)
			continue
		}
		fmt.Printf("Successfully connected to local node: %s (current block: %d)\n", url, blockNumber)

		clients = append(clients, client)
	}

	if len(clients) == 0 {
		return nil, fmt.Errorf("failed to connect to local node")
	}

	return &ZkSyncClient{
		clients: clients,
		urls:    rpcURLs,
		current: 0,
	}, nil
}

// Client 返回当前可用的客户端
func (z *ZkSyncClient) Client() *ethclient.Client {
	z.mu.RLock()
	defer z.mu.RUnlock()
	return z.clients[z.current]
}

// SwitchToNextNode 切换到下一个可用的节点
func (z *ZkSyncClient) SwitchToNextNode() {
	z.mu.Lock()
	defer z.mu.Unlock()
	z.current = (z.current + 1) % len(z.clients)
}

// Close 关闭所有客户端连接
func (z *ZkSyncClient) Close() {
	z.mu.Lock()
	defer z.mu.Unlock()
	for _, client := range z.clients {
		client.Close()
	}
}

// HealthCheck 检查所有节点的健康状态
func (z *ZkSyncClient) HealthCheck() map[string]bool {
	z.mu.RLock()
	defer z.mu.RUnlock()

	health := make(map[string]bool)
	for i, client := range z.clients {
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		_, err := client.BlockNumber(ctx)
		cancel()
		health[z.urls[i]] = err == nil
	}
	return health
}
